﻿using System;
using System.Text;

namespace cc.hanzs.json {
    public class JSONTokener {
        private int myIndex;
        private String mySource;
        private static JSONTokener d副本_JSONTokener = new JSONTokener();

        private JSONTokener() {
        }

        public static JSONTokener d副本(String s) {
            if (s == null) {
                throw new JSONException("待解析文本不可为空");
            }
            JSONTokener jd = (JSONTokener) d副本_JSONTokener.MemberwiseClone();
            jd.myIndex = 0;
            jd.mySource = s;
            return jd;
        }

        public void back() {
            if (this.myIndex > 0) {
                this.myIndex -= 1;
            }
        }

        private bool more() {
            return this.myIndex < this.mySource.Length;
        }

        public char next() {
            if (more()) {
                char c = this.mySource.ToCharArray(this.myIndex, 1)[0];
                this.myIndex += 1;
                return c;
            }
            return (char)0;
        }

        private String next(int n) {
            int i = this.myIndex;
            int j = i + n;
            if (j >= this.mySource.Length) {
                throw new JSONException("Substring bounds error");
            }
            this.myIndex += n;
            return this.mySource.Substring(i, n);
        }

        public char nextClean() {
            for (;;) {
                char c = next();
                if (c == '/') {
                    switch (next()) {
                        case '/':
                            do {
                                c = next();
                            } while (c != '\n' && c != '\r' && c != 0);
                            break;
                        case '*':
                            for (;;) {
                                c = next();
                                if (c == 0) {
                                    throw new JSONException("Unclosed comment.");
                                }
                                if (c == '*') {
                                    if (next() == '/') {
                                        break;
                                    }
                                    back();
                                }
                            }
                            break;
                        default:
                            back();
                            return '/';
                    }
                } else if (c == '#') {
                    do {
                        c = next();
                    } while (c != '\n' && c != '\r' && c != 0);
                } else if (c == 0 || c > ' ') {
                    return c;
                }
            }
        }

        private String nextString(char quote) {
            char c;
            StringBuilder sb = new StringBuilder();
            for (;;) {
                c = next();
                switch (c) {
                    case (char)0:
                    case '\n':
                    case '\r':
                        throw new JSONException("Unterminated string");
                    case '\\':
                        c = next();
                        switch (c) {
                            case 'b':
                                sb.Append('\b');
                                break;
                            case 't':
                                sb.Append('\t');
                                break;
                            case 'n':
                                sb.Append('\n');
                                break;
                            case 'f':
                                sb.Append('\f');
                                break;
                            case 'r':
                                sb.Append('\r');
                                break;
                            case 'u':
                                sb.Append(System.Convert.ToChar(System.Convert.ToUInt16(next(4), 16)));
                                break;
                            case 'x':
                                sb.Append(System.Convert.ToChar(System.Convert.ToUInt16(next(2), 16)));
                                break;
                            default:
                                sb.Append(c);
                                break;
                        }
                        break;
                    default:
                        if (c == quote) {
                            return sb.ToString();
                        }
                        sb.Append(c);
                        break;
                }
            }
        }

        public Object nextValue(Object parent) {
            char c = nextClean();
            String s;

            switch (c) {
                case '"':
                case '\'':
                    return nextString(c);
                case '{':
                    back();
                    JSONObject d1 = JSONObject.d副本();
                    d1.parent = parent;
                    d1.set(this);
                    return d1;
                case '[':
                    back();
                    JSONArray d2 = JSONArray.d副本();
                    d2.parent = parent;
                    d2.set(this);
                    return d2;
            }

            /*
             * Handle unquoted text. This could be the values true, false, or null, or it can be a number. An implementation (such as this one) is allowed
             * to also accept non-standard forms.
             *
             * Accumulate characters until we reach the end of the text or a formatting character.
             */
            StringBuilder sb = new StringBuilder();
            char b = c;
            while (c >= ' ' && ",:]}\\\"[{;=#".IndexOfAny(new char[]{c},0,11) < 0) {//去掉/
                sb.Append(c);
                c = next();
            }
            back();

            /*
             * If it is true, false, or null, return the proper value.
             */
            s = sb.ToString().Trim();
            if (s.Equals("")) {
                throw new JSONException("Missing value.");
            }
            if (s.ToLower().Equals("true")) {
                return true;
            }
            if (s.ToLower().Equals("false")) {
                return false;
            }
            if (s.ToLower().Equals("null")) {
                return null;
            }

            /*
             * If it might be a number, try converting it. We support the 0- and 0x- conventions. If a number cannot be produced, then the value will just
             * be a string. Note that the 0-, 0x-, plus, and implied string conventions are non-standard. A JSON parser is free to accept non-JSON forms as
             * long as it accepts all correct JSON forms.
             */
            if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
                if (b == '0') {
                    if (s.Length > 2 && (s.ToCharArray(1, 1)[0] == 'x' || s.ToCharArray(1, 1)[0] == 'X')) {//16进制
                        try {
                            return System.Convert.ToInt32(s.Substring(2), 16);
                        } catch (Exception) {
                            /*
                             * Ignore the error
                             */
                        }
                    } else {
                        try {
                            return System.Convert.ToInt32(s, 8);
                        } catch (Exception) {
                            /*
                             * Ignore the error
                             */
                        }
                    }
                }
                try {
                    return System.Convert.ToInt32(s, 10);
                } catch (Exception) {
                    try {
                        return System.Convert.ToInt64(s, 10);
                    } catch (Exception) {
                        try {
                            return System.Convert.ToDouble(s);
                        } catch (Exception) {
                            /*
                             * Ignore the error
                             */
                        }
                    }
                }
            }
/*            if (parent != null) {
                if (s.StartsWith("/")) {//仅支持根路径
                    return cc.hanzs.json.JSONPath.d副本(s);
                }
            }
 */
            return s;
        }

        public char skipTo(char to) {
            char c;
            int index = this.myIndex;
            do {
                c = next();
                if (c == 0) {
                    this.myIndex = index;
                    return c;
                }
            } while (c != to);
            back();
            return c;
        }

        public void skipPast(String to) {
            this.myIndex = this.mySource.IndexOf(to, this.myIndex);
            if (this.myIndex < 0) {
                this.myIndex = this.mySource.Length;
            } else {
                this.myIndex += to.Length;
            }
        }

        public String toString() {
            return " at character " + this.myIndex + " of " + this.mySource;
        }
    }
}
